package com.example.onlinemonitoring.comCenter;

import com.example.onlinemonitoring.Util.CRC16;
import com.example.onlinemonitoring.Util.CommPortManager;
import com.example.onlinemonitoring.Util.HexUtil;
import com.example.onlinemonitoring.autoRun.ComRunner;
import com.example.onlinemonitoring.model.Appdevice;
import com.example.onlinemonitoring.model.Sf6history;
import com.example.onlinemonitoring.model.Sf6sensor;
import com.example.onlinemonitoring.serviceImpl.Sf6sensorServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.net.SocketException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * 微水
 */
@Service("sf6Com")
@Scope("prototype")
public class Sf6Com extends CommPortManager {
    @Autowired
    private Sf6sensorServiceImpl sf6serviceimpl;
    public float[] dyxrecvdata = new float[5];

    @Override
    public void receiveData(String str) {
        str = str.toUpperCase();
        setText(str);
        switch (ad.getBrand()) {
            case "采购":
                CG(str);
                break;
            case "自产":
                ZC(str);
                break;
            case "大姚县":
                DYX(str);
                break;
            default:
                return;
        }
    }

    private void read61850(String str) {
        Sf6sensor currrecord = new Sf6sensor();
        currrecord.setStationid(ad.getStationid());
        currrecord.setDevicegroup(ad.getDevicegroup());
        List<Sf6sensor> lastrecordlist = sf6serviceimpl.getLists(currrecord);
        if (lastrecordlist.size() != 0) {
            if (lastrecordlist.get(0).getStyle61850() != null) {
                String[] style = lastrecordlist.get(0).getStyle61850().split(",");
                for (String s : style) {
                    map61850.put(s.split("\\|")[0], s.split("\\|")[1]);
                }
            }
        }
        for (Sf6sensor lastrecord : lastrecordlist) {
            currrecord.setDeviceaddr(lastrecord.getDeviceaddr());
            String alm = "";
            try {
                currrecord.setLasttemperature(read61850FloatValue(
                        String.format(isnull(map61850.get("Tmp")), lastrecord.getDeviceaddr())));
                currrecord.setLastpressure(read61850FloatValue(
                        String.format(isnull(map61850.get("Pres")), lastrecord.getDeviceaddr())));
                currrecord.setLastdensity(read61850FloatValue(
                        String.format(isnull(map61850.get("Den")), lastrecord.getDeviceaddr())));
                currrecord.setLastppm(read61850FloatValue(
                        String.format(isnull(map61850.get("Mst")), lastrecord.getDeviceaddr())));
                currrecord.setLastchangya(read61850FloatValue(
                        String.format(isnull(map61850.get("DewPo")), lastrecord.getDeviceaddr())));
                alm += read61850IntValue(
                        String.format(isnull(map61850.get("SupDevRun")), lastrecord.getDeviceaddr())) == 1 ? "运行告警,"
                                : "";
                currrecord.setLastcommunicationstatus(read61850IntValue(
                        String.format(isnull(map61850.get("MoDevConf")), lastrecord.getDeviceaddr())));
            } catch (SocketException e) {
                if (Close()) {
                    sf6serviceimpl.UpdateStatus(ad, 1);
                    ComRunner.netmap.remove(ad.getId());
                }
            } catch (Exception e) {
                setText("读取数据出错！" + e.toString());
            }

            if (alm.equals("")) {
                currrecord.setLastalarmlevel(0);
                currrecord.setLastalarmmessage(alm);
                GetNormalAlarm("微水" + lastrecord.getDeviceaddr(), lastrecord.getDevicegroup(),
                        lastrecord.getDeviceaddr(), 0,
                        lastrecord.getPointname(), "", false);
                setText("无报警");
            } else {
                currrecord.setLastalarmlevel(2);
                currrecord.setLastalarmmessage(alm);
                GetNormalAlarm("微水" + lastrecord.getDeviceaddr(), lastrecord.getDevicegroup(),
                        lastrecord.getDeviceaddr(), 0,
                        lastrecord.getPointname(), alm, true);
                setText(alm);
            }

            currrecord.setLastdatatime(new Date());
            currrecord.setLasthisdatatime(addHistory(lastrecord));
            sf6serviceimpl.Update(currrecord, false);
            StringBuilder str2 = new StringBuilder();
            str2.append("微水设备返回数据： 站点号：1 地址" + currrecord.getDeviceaddr());
            str2.append("温度：" + currrecord.getLasttemperature());
            str2.append("湿度：" + currrecord.getLastpressure());
            str2.append("压力：" + currrecord.getLastdensity());
            str2.append("微水：" + currrecord.getLastppm());
            str2.append("露点：" + currrecord.getLastchangya());
            setText(str2.toString());
        }
    }

    private void CG(String str) {
        if (str.length() != 66)
            return;
        String addrstr = str.substring(0, 2);
        Integer addrint = parseHex4(addrstr);

        reSend[addrindex] = 0;
        addrindex++;
        float pressure = 0, temperature = 0, relativeHumidity = 0, density = 0, pressure20 = 0,
                waterVaporPartialPressure = 0, dewPoint = 0, PPMVolumeFraction = 0;
        temperature = parseHex4(str.substring(6, 10)) * 0.01f;
        dewPoint = parseHex4(str.substring(10, 14)) * 0.01f;
        pressure = parseHex4(str.substring(18, 22));
        pressure20 = parseHex4(str.substring(26, 30));
        waterVaporPartialPressure = parseHex4(str.substring(34, 38)) * 0.01f;
        PPMVolumeFraction = parseHex4(str.substring(42, 46));
        relativeHumidity = parseHex4(str.substring(58, 62));
        SensorData(addrint, new Date(), pressure, temperature, relativeHumidity, density, waterVaporPartialPressure,
                dewPoint, PPMVolumeFraction, pressure20);
    }

    private void ZC(String str) {
        if (str.length() != 66)
            return;
        String addrstr = str.substring(0, 2);
        Integer addrint = parseHex4(addrstr);

        reSend[addrindex] = 0;
        addrindex++;
        float pressure = 0, temperature = 0, relativeHumidity = 0, density = 0, pressure20 = 0,
                waterVaporPartialPressure = 0, dewPoint = 0, PPMVolumeFraction = 0;
        byte[] mybyte_pressure = HexUtil.hexString2Bytes(str.substring(6, 14));
        pressure = HexUtil.byte2float(mybyte_pressure);

        byte[] mybyte_temperature = HexUtil.hexString2Bytes(str.substring(14, 22));
        temperature = HexUtil.byte2float(mybyte_temperature);
        if (temperature < -50 || temperature > 80)
            return;

        byte[] mybyte_relativeHumidity = HexUtil.hexString2Bytes(str.substring(22, 30));
        relativeHumidity = HexUtil.byte2float(mybyte_relativeHumidity);

        byte[] mybyte_density = HexUtil.hexString2Bytes(str.substring(30, 38));
        density = HexUtil.byte2float(mybyte_density);

        pressure20 = density / 1000;
        pressure20 = (54.525F - 0.12103722F * 293.2F) * pressure20 * pressure20 * pressure20
                + (0.14307F * 293.2F - 75) * pressure20 * pressure20 + 0.057F * 293.2F * pressure20;

        byte[] mybyte_waterVaporPartialPressure = HexUtil.hexString2Bytes(str.substring(38, 46));
        waterVaporPartialPressure = HexUtil.byte2float(mybyte_waterVaporPartialPressure);

        byte[] mybyte_dewPoint = HexUtil.hexString2Bytes(str.substring(46, 54));
        dewPoint = HexUtil.byte2float(mybyte_dewPoint);

        byte[] mybyte_PPMVolumeFraction = HexUtil.hexString2Bytes(str.substring(54, 62));
        PPMVolumeFraction = HexUtil.byte2float(mybyte_PPMVolumeFraction);
        SensorData(addrint, new Date(), pressure, temperature, relativeHumidity, density, waterVaporPartialPressure,
                dewPoint, PPMVolumeFraction, pressure20);
    }

    private void DYX(String str) {
        try {
            int singlelen = 22;
            for (int i = 0; i < str.length() / singlelen; i++) {
                String cstr = str.substring(singlelen * i, singlelen * (i + 1));
                DYXS(cstr);
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    private void DYXS(String str) {

        float fuhao = 1.0f;
        if (str.substring(6, 8).equals("01")) {
            fuhao = -1.0f;
        }
        int a1 = Integer.parseInt(str.substring(9, 10));
        int a2 = Integer.parseInt(str.substring(11, 12));
        int a3 = Integer.parseInt(str.substring(13, 14));
        int a4 = Integer.parseInt(str.substring(15, 16));
        switch (str.substring(2, 4)) {
            case "C0":
                dyxrecvdata[0] = (a1 * 100f + a2 * 10f + a3 + a4 / 10f) * fuhao;
                break;
            case "C1":
                dyxrecvdata[1] = (a1 * 1000f + a2 * 100f + a3 * 10 + a4) * fuhao;
                break;
            case "C2":
                dyxrecvdata[2] = (a3 / 10f + a4 / 100f) * fuhao;
                break;
            case "C3":
                dyxrecvdata[3] = (a3 / 10f + a4 / 100f) * fuhao;
                break;
            case "C4":
                dyxrecvdata[4] = (a1 * 100f + a2 * 10f + a3 + a4 / 10f) * fuhao;
                break;
            default:
                break;
        }
        if (str.substring(2, 4).equals("C4")) {
            reSend[addrindex] = 0;
            addrindex++;
            SensorData(parseHex4(str.substring(4, 6)), new Date(), dyxrecvdata[2], dyxrecvdata[0], 100f, dyxrecvdata[3],
                    0f,
                    dyxrecvdata[4], dyxrecvdata[1], 0f);
        }
    }

    void SensorData(int addrint, Date nowtime, float pressure, float temperature, float relativeHumidity,
            float density, float waterVaporPartialPressure, float dewPoint, float PPMVolumeFraction, float pressure20) {
        if (ad.getBrand().equals("自产")) {
            if (relativeHumidity <= 0.5) {
                Random rd = new Random();
                relativeHumidity = (float) 0.01 * (rd.nextInt(20) + 80);
                float temp = (10.286f * temperature + 661.13f) / (temperature + 273.3f);
                double ps = Math.pow((double) 0, (double) temp) / 1000000;
                float pw = (float) ps * relativeHumidity * 0.01f;
                temp = 0.66077f + 7.5f * temperature / (237.3f + temperature)
                        + (float) Math.log10((double) relativeHumidity) - 2f;
                dewPoint = ((0.66077f - temp) * 237.3f) / (temp - 8.16077f);
                PPMVolumeFraction = pw / pressure * 1000000;
            }
            if (PPMVolumeFraction > 99999)
                PPMVolumeFraction = 99999;
        }
        setText("解析日新SF6微水密度通信数据：站点号：1 监测点" + addrint);
        setText("压力：" + pressure + "MPa");
        setText("压力(20℃)：" + pressure20 + "MPa");
        setText("温度：" + temperature + "℃");
        setText("相对湿度：" + relativeHumidity + "%");
        setText("密度：" + density + "kg/m³");
        setText("常压露点(20℃)：" + waterVaporPartialPressure + "MPa");
        setText("带压露点：" + dewPoint + "℃");
        setText("微水体积分数：" + PPMVolumeFraction + "ppmV");

        Sf6sensor sf6 = new Sf6sensor();
        sf6.setStationid(ad.getStationid());
        sf6.setDevicegroup(ad.getDevicegroup());
        sf6.setDeviceaddr(addrint);
        Sf6sensor record = sf6serviceimpl.getModel(sf6);

        if (record == null) {
            setText("当前数据库无监测点：" + addrint + " ！ 请先添加该监测点！");
            return;
        }
        sf6.setLasttemperature(temperature);
        sf6.setLasthumidity(relativeHumidity);
        sf6.setLastpressure(pressure);
        sf6.setLastpressure20(pressure20);
        sf6.setLastdensity(density);
        sf6.setLastdaiya(waterVaporPartialPressure);
        sf6.setLastchangya(dewPoint);
        sf6.setLastppm(PPMVolumeFraction);
        sf6.setDeviceaddr(addrint);
        sf6.setStationid(ad.getStationid());
        sf6.setLastdatatime(nowtime);

        AddAndUpdate(sf6, record);
    }

    @Transactional
    private void AddAndUpdate(Sf6sensor sf6, Sf6sensor record) {
        int alarmLevel = 0;// 报警等级
        String alarmMessage = "";// 报警消息
        List<Integer> array = new ArrayList<>();
        sf6.setLastchangyaalarmstatus(
                GetAlarmStatus(isnull(sf6.getLastchangya()), isnull(record.getChangyaalarmvalue()),
                        isnull(record.getChangyaalarmrelievevalue()), isnull(record.getChangyawarnvalue()),
                        isnull(record.getChangyawarnrelievevalue()),
                        isnull(record.getLastchangyaalarmstatus()), true, "常压露点", record.getDevicegroup(),
                        record.getDeviceaddr(),
                        record.getPointname()));
        alarmMessage += GetAlarmMessage(sf6.getLastchangyaalarmstatus(), "常压露点");
        array.add(sf6.getLastchangyaalarmstatus());
        if (ad.getBrand().equals("采购")) {
            sf6.setLastdaiyaalarmstatus(
                    GetAlarmStatus(isnull(sf6.getLastdaiya()), isnull(record.getDaiyaalarmvalue()),
                            isnull(record.getDaiyaalarmrelievevalue()), isnull(record.getDaiyawarnvalue()),
                            isnull(record.getDaiyawarnrelievevalue()),
                            isnull(record.getLastdaiyaalarmstatus()), true, "带压露点", record.getDevicegroup(),
                            record.getDeviceaddr(),
                            record.getPointname()));
            alarmMessage += GetAlarmMessage(sf6.getLastdaiyaalarmstatus(), "带压露点");
            array.add(sf6.getLastdaiyaalarmstatus());

            sf6.setLastpressure20alarmstatus(
                    GetAlarmStatus(isnull(sf6.getLastpressure20()), isnull(record.getPressure20alarmvalue()),
                            isnull(record.getPressure20alarmrelievevalue()), isnull(record.getPressure20warnvalue()),
                            isnull(record.getPressure20warnrelievevalue()),
                            isnull(record.getLastpressure20alarmstatus()), false, "20℃压力", record.getDevicegroup(),
                            record.getDeviceaddr(),
                            record.getPointname()));
            alarmMessage += GetAlarmMessage(sf6.getLastpressure20alarmstatus(), "20℃压力");
            array.add(sf6.getLastpressure20alarmstatus());
        }

        sf6.setLastdensityalarmstatus(GetAlarmStatus(isnull(sf6.getLastdensity()),
                isnull(record.getDensityalarmvalue()),
                isnull(record.getDensityalarmrelievevalue()), isnull(record.getDensitywarnvalue()),
                isnull(record.getDensitywarnrelievevalue()),
                isnull(record.getLastdensityalarmstatus()), false, "密度", record.getDevicegroup(),
                record.getDeviceaddr(), record.getPointname()));
        alarmMessage += GetAlarmMessage(sf6.getLastdensityalarmstatus(), "密度");
        array.add(sf6.getLastdensityalarmstatus());
        sf6.setLasthumidityalarmstatus(
                GetAlarmStatus(isnull(sf6.getLasthumidity()), isnull(record.getHumidityalarmvalue()),
                        isnull(record.getHumidityalarmrelievevalue()), isnull(record.getHumiditywarnvalue()),
                        isnull(record.getHumiditywarnrelievevalue()),
                        isnull(record.getLasthumidityalarmstatus()), true, "湿度", record.getDevicegroup(),
                        record.getDeviceaddr(),
                        record.getPointname()));
        alarmMessage += GetAlarmMessage(sf6.getLasthumidityalarmstatus(), "湿度");
        array.add(sf6.getLasthumidityalarmstatus());
        sf6.setLastppmalarmstatus(GetAlarmStatus(isnull(record.getLastppm()), isnull(record.getPpmalarmvalue()),
                isnull(record.getPpmalarmrelievevalue()), isnull(record.getPpmwarnvalue()),
                isnull(record.getPpmwarnrelievevalue()),
                isnull(record.getLastppmalarmstatus()), true, "微水", record.getDevicegroup(), record.getDeviceaddr(),
                record.getPointname()));
        alarmMessage += GetAlarmMessage(sf6.getLastppmalarmstatus(), "微水");
        array.add(sf6.getLastppmalarmstatus());
        sf6.setLastpressurealarmstatus(
                GetAlarmStatus(isnull(record.getLastpressure()), isnull(record.getPressurealarmvalue()),
                        isnull(record.getPressurealarmrelievevalue()), isnull(record.getPressurewarnvalue()),
                        isnull(record.getPressurewarnrelievevalue()),
                        isnull(record.getLastpressurealarmstatus()), false, "压力", record.getDevicegroup(),
                        record.getDeviceaddr(),
                        record.getPointname()));
        alarmMessage += GetAlarmMessage(sf6.getLastpressurealarmstatus(), "压力");
        array.add(sf6.getLastpressurealarmstatus());

        sf6.setLasttemperaturealarmstatus(
                GetAlarmStatus(isnull(record.getLasttemperature()), isnull(record.getTemperaturealarmvalue()),
                        isnull(record.getTemperaturealarmrelievevalue()), isnull(record.getTemperaturewarnvalue()),
                        isnull(record.getTemperaturewarnrelievevalue()),
                        isnull(record.getLasttemperaturealarmstatus()), true, "温度", record.getDevicegroup(),
                        record.getDeviceaddr(),
                        record.getPointname()));
        alarmMessage += GetAlarmMessage(sf6.getLasttemperaturealarmstatus(), "温度");
        array.add(sf6.getLasttemperaturealarmstatus());
        alarmLevel = HexUtil.MAX(array);
        sf6.setLastalarmlevel(alarmLevel);
        sf6.setLastalarmmessage(alarmMessage);
        sf6.setLastcommunicationstatus(0);
        sf6.setLasthisdatatime(addHistory(record));
        if (sf6serviceimpl.Update(sf6, false) == 0) {
            setText("更新实时数据失败，请检查数据库连接");
        }
    }

    private Date addHistory(Sf6sensor sensor) {
        if (sensor != null) {
            if (sensor.getLasthisdatatime() == null) {
                add(sensor);
                return new Date();
            } else {
                long lasttime = 0;
                long nowtime = 0;
                try {
                    lasttime = HexUtil.todate(sensor.getLasthisdatatime()).getTime();
                    nowtime = HexUtil.todate(new Date()).getTime();
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                int timersp = 60000;
                if (sensor.getLastalarmlevel() != 0) {
                    timersp = ad.getHisalarmtimersp() * 1000;
                } else {
                    timersp = ad.getHistimersp() * 1000;
                }
                if (lasttime + timersp < nowtime) {
                    add(sensor);
                    return new Date();
                }
            }
        }
        return null;
    }

    private void add(Sf6sensor sensor) {
        Sf6history his = new Sf6history();
        his.setDeviceaddr(sensor.getDeviceaddr());
        his.setDevicegroup(sensor.getDevicegroup());
        his.setInuse(sensor.getInuse());
        his.setAlarmlevel(sensor.getLastalarmlevel());
        his.setAlarmmessage(sensor.getLastalarmmessage());
        his.setChangya(sensor.getLastchangya());
        his.setChangyaalarmstatus(sensor.getLastchangyaalarmstatus());
        his.setDaiya(sensor.getLastdaiya());
        his.setDatatime(sensor.getLastdatatime());
        his.setDensity(sensor.getLastdensity());
        his.setDensityalarmstatus(sensor.getLastdensityalarmstatus());
        his.setHumidity(sensor.getLasthumidity());
        his.setHumidityalarmstatus(sensor.getLasthumidityalarmstatus());
        his.setPpm(sensor.getLastppm());
        his.setPpmalarmstatus(sensor.getLastppmalarmstatus());
        his.setPressure(sensor.getLastpressure());
        his.setPressurealarmstatus(sensor.getLastpressurealarmstatus());
        his.setStandby(sensor.getLaststandby());
        his.setTemperature(sensor.getLasttemperature());
        his.setTemperaturealarmstatus(sensor.getLasttemperaturealarmstatus());
        his.setMemo(sensor.getMemo());
        his.setPointname(sensor.getPointname());
        his.setStationid(sensor.getStationid());
        his.setStyle(sensor.getStyle());
        sf6serviceimpl.Add(his);
    }

    // 指定使用beanname为threadPool的线程池
    @Async("threadPool")
    public void startSendThread(Appdevice Appdevice) throws Exception {
        if (Appdevice.getBrand().equals("西电")) {
            return;
        }
        if (!Appdevice.getBrand().equals("大姚县")) {
            checkType = "crc16";
        }
        issend.put(Thread.currentThread().getId(), true);
        String cstr = "";
        String cmdtype = "";
        String nametype = "";
        int timersp = (int) Math.round(Appdevice.getTimersp() * 1000);

        while (issend.get(Thread.currentThread().getId()) != null) {
            if (isrun) {
                if (addrindex > Appdevice.getAddrmax() || addrindex < Appdevice.getAddrmin())
                    addrindex = Appdevice.getAddrmin();
                cstr = String.format(Appdevice.getCmd(), String.format("%02X", addrindex));
                if (checkType.equals("crc16")) {
                    cstr = cstr + CRC16.calcCrc16(cstr);
                }
                Send(cstr);
                if (reSend[addrindex] > 3) {
                    sf6serviceimpl.UpdateStatus(ad, addrindex, 1);
                    reSend[addrindex] = 0;
                    addrindex++;
                }
                reSend[addrindex]++;
            } else if (rescode != 0) {
                setText(resmsg[rescode]);
            }
            Thread.sleep(timersp);
        }
    }
}
